/*--------------------------------------------------------------------------------------*\
**
** puzzle_window.cpp
**
** Heroes IV
** Copyright 2000, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "puzzle_window.h"

#include "adventure_frame.h"
#include "adaptor_handler.h"
#include "adventure_map.h"
#include "adventure_map_window.h"
#include "adventure_treasure_map.h"
#include "bitmap_group.h"
#include "bitmap_group_ptr.h"
#include "bitmap_group_window.h"
#include "bound_handler.h"
#include "button.h"
#include "button_cache.h"
#include "enum_operations.h"
#include "external_string.h"
#include "format_string.h"
#include "idle_processor.h"
#include "interface_help.h"
#include "item_help_block.h"
#include "player.h"
#include "replace_keywords.h"
#include "standard_fonts.h"

extern t_button_cache g_ok_button;

t_button* create_blacksmith_button( std::string const& name, t_bitmap_group_ptr bitmap_ptr, t_window *parent_window );

namespace 
{ // unnamed namespace
    t_bitmap_group_cache     k_puzzle_background_bitmaps ("dialog.puzzle"); //_screen.layout");

    // Need text to say, "x out of y obelisks visited."
    t_external_string const k_text_puzzle_visit( "puzzle_visit.misc" );
    t_external_string const k_text_puzzle_intro( "puzzle_intro.misc" );
    t_external_string const k_text_puzzle_title( "puzzle_title.misc" );
    t_external_string const k_text_obelisk_button( "puzzle_obelisk.misc" );

    int const k_total_number_of_pieces = 30;
	const int k_fade_time = 20;
	const int k_fade_alpha_value = k_fade_time - 5;

	class t_fader : public t_idle_processor
	{
	public:
		t_fader( t_puzzle_window * puzzle_window );
		virtual void on_idle();
	protected:
        t_puzzle_window *       m_puzzle_window_ptr;
	};
}; // end unnamed namespace

/*
** Idle processor - for fading out puzzle bitmap.
*/
t_fader::t_fader( t_puzzle_window * puzzle_window ) 
        : t_idle_processor(0, k_fade_time )
{
    m_puzzle_window_ptr = puzzle_window;
}

void t_fader::on_idle()
{
    m_puzzle_window_ptr->on_idle();
}

/*
** Obelisk colors.
*/
std::string const colors_table[k_obelisk_color_count] =
{
    "gold",
	"red",
	"blue",
	"white",
	"black",
	"green",
	"purple",
	//"pink", ??
	"orange",
	"yellow",
	"brown",
	"silver",
	"bronze"
};

/*---------------------------------------------------------------------------------------*\
** Puzzle window constructer.
\*---------------------------------------------------------------------------------------*/
t_puzzle_window::t_puzzle_window( t_window* parent, t_adventure_frame * frame_ptr, t_player * player_ptr, int selected_obelisk ) 
                   : t_window( k_completely_transparent, parent )
{
	t_screen_rect rect;
    int i;
	t_help_block const&		help = get_help_block( "puzzle_map" );
	//t_properties    properties = get_obelisk_properties();

    m_player_ptr = player_ptr;
    m_adventure_frame_ptr = frame_ptr;
    m_map_ptr = frame_ptr->get_map();
    m_selected_color = (t_obelisk_color)selected_obelisk;
    m_treasure_map_window_ptr = NULL;
    m_fading = 0;
	m_fader = new t_fader( this );
    
	/*
    ** Load bitmaps, set window position.
    */
	t_screen_rect parent_rect;

	m_background_bitmaps_ptr = k_puzzle_background_bitmaps.get();
	parent_rect = get_parent()->get_client_rect();
	rect = m_background_bitmaps_ptr->get_rect();
	rect += (parent_rect.size() - rect.size()) / 2;
	init( rect );

	/*
    ** Create background bitmap.
    */
	t_bitmap_layer const*   layer;
	t_window*               window;
	t_window*               background;
	t_screen_point          origin(0,0);

	layer = m_background_bitmaps_ptr->find( "background" );
	background = new t_bitmap_layer_window( layer, origin, this );

	//origin = -layer->get_rect().top_left();

    /*
    ** Text.
    */
	t_text_window*          text_window_ptr;

	rect = m_background_bitmaps_ptr->find( "title" )->get_rect(); // + origin;
	text_window_ptr  = new t_text_window( get_font( 18 ), rect, this, "", t_pixel_24(0,0,0) );
    text_window_ptr->set_text ( k_text_puzzle_title );
	text_window_ptr->set_center_horizontal();

    /*
    ** Create buttons.
    */
	t_button            *button_ptr;
	t_help_block const& shared_help_block = get_help_block( "shared" );

	// Create close button
	rect = m_background_bitmaps_ptr->find( "close_button" )->get_rect();
	button_ptr = new t_button( g_ok_button.get(), rect.top_left(), this );
	button_ptr->set_click_handler( bound_handler( *this, &t_puzzle_window::close_click ));
	set_help( button_ptr, shared_help_block, "ok" );

    // Create all obelisk buttons:
    t_obelisk_color color;
    bool    any_obelisks = false;

    for (color = k_obelisk_gold; color < k_obelisk_color_count; enum_incr( color ))
    {
        // Any obelisks of this color on map?
        if ( m_map_ptr->get_required_obelisks ( color ) > 0 )
        {
            //if (color != k_obelisk_pink)
            {
                button_ptr = create_blacksmith_button( colors_table[ color ], m_background_bitmaps_ptr, this );
	            button_ptr->set_click_handler( add_2nd_argument( bound_handler( *this, &t_puzzle_window::obelisk_clicked ), color ));
	            button_ptr->set_help_balloon_text( k_text_obelisk_button );
                set_help( button_ptr, help, colors_table[ color ] );
            
                any_obelisks = true;
            }
        }
    }

    // Show text.
	std::string intro_text;

    if (any_obelisks)
	    intro_text = k_text_puzzle_intro;
    else
	    intro_text = help.get_help( "empty" );

	rect = m_background_bitmaps_ptr->find( "text" )->get_rect(); // + origin;
	m_visit_text_window_ptr  = new t_text_window( get_font( 18 ), rect, this, " ", t_pixel_24(0,0,0) );
    m_visit_text_window_ptr->set_text( intro_text );

    /*
    ** Init puzzle pieces.
    */
	std::string             puzzle_piece_name;

    // Get appropriate puzzle bitmap pointer?
	m_puzzle_bitmaps_ptr = k_puzzle_background_bitmaps.get();
    for (i = 0; i<k_total_number_of_pieces; i++)
    {
		puzzle_piece_name = format_string ( "piece_%d", (i+1) );

    	layer = m_puzzle_bitmaps_ptr->find( puzzle_piece_name );
	    window = new t_bitmap_layer_window( layer, origin, this ); //background );
	    window->set_visible (false);
        m_puzzle_pieces.push_back( window );
    }

    // Init obelisk puzzle.
    obelisk_clicked( NULL, (t_obelisk_color)selected_obelisk );
}

t_puzzle_window::~t_puzzle_window()
{
    delete m_fader;
}

/*
** order parameter specifies order to reveal picture.
*/
void t_puzzle_window::reveal_picture ( int number_of_pieces_to_reveal, int *order )
{
    int i;

#if (0)
    if (order)
    {
        for (i = 0; i<k_total_number_of_pieces; i++)
        {
            if (i == *order)
                m_puzzle_pieces[i]->set_visible( true );
            order++;
        }
    }
#endif

    for (i = 0; i<m_puzzle_pieces.size(); i++)
    {
        if (i < number_of_pieces_to_reveal)
        {
            m_puzzle_pieces[i]->set_visible( true );
            //m_puzzle_pieces[i]->move_to_front();
        }
        else
        {
            m_puzzle_pieces[i]->set_visible( false );
        }
    }
}

/*
** Show map with artifact location.
*/
void t_puzzle_window::display_artifact_location()
{
    // Valid color?
    if ((m_selected_color < 0) || (m_selected_color > k_obelisk_color_count))
        return;

    int i;
    t_level_map_point_2d artifact_position = m_map_ptr->get_obelisk_artifact_position( m_selected_color );

    // Valid artifact position?
    if ((artifact_position.row == -1) && (artifact_position.column == -1))
        return;

	t_bitmap_layer const*   layer;
	layer = m_background_bitmaps_ptr->find( "puzzle_area" );
    t_screen_rect   view_rect = layer->get_rect();

    /*
    ** Show artifact treasure map.
    */
    m_treasure_map_window_ptr = new t_adventure_treasure_map( view_rect, m_adventure_frame_ptr, this, artifact_position );
    m_treasure_map_window_ptr->set_visible( true );
    m_treasure_map_window_ptr->center_view( artifact_position );
	m_treasure_map_window_ptr->enable_animation( false );
	//m_treasure_map_window_ptr->draw_grayscale();

    /*
    ** Init blended bitmap puzzle pieces.  Don't use m_puzzle_pieces for
    ** speed reasons (blended takes longer).
    */
	std::string             puzzle_piece_name;
	t_blended_bitmap_window*               window;
    m_puzzle_cover_pieces.clear();
    for (i = 0; i<k_total_number_of_pieces; i++)
    {
		puzzle_piece_name = format_string ( "piece_%d", (i+1) );

    	layer = m_puzzle_bitmaps_ptr->find( puzzle_piece_name );
	    window = new t_blended_bitmap_window( layer, -view_rect.top_left(), m_treasure_map_window_ptr );
	    window->set_visible ( true );
		window->set_alpha( k_fade_alpha_value );
        m_puzzle_cover_pieces.push_back( window );
    }
    m_fading = k_fade_alpha_value;

}

void t_puzzle_window::on_idle()
{
    if (m_fading > 0)
    {
        int i;

        /*
        ** Create grayscale - put this here because we want to make sure
        ** image is in buffer before we convert to grayscale.
        */
        if (m_fading == k_fade_alpha_value)
	        m_treasure_map_window_ptr->draw_grayscale();

        m_fading--;
        for (i = 0; i<m_puzzle_cover_pieces.size(); i++)
            m_puzzle_cover_pieces[i]->set_alpha (m_fading);
    }
}

// button_ptr is NULL if called explicitly.
void t_puzzle_window::obelisk_clicked( t_button *button_ptr, t_obelisk_color color )
{
    // Valid color?
    if ((color < 0) || (color > k_obelisk_color_count))
        return;

    // If not called explicitly, check if it's the same color.
    if ((button_ptr != NULL) && (color == m_selected_color))
        return;

	t_help_block const&		help = get_help_block( "puzzle_map" );

    if (m_treasure_map_window_ptr)
        m_treasure_map_window_ptr->close();
    m_fading = 0;

    m_selected_color = color;
    int required_obelisks = m_map_ptr->get_required_obelisks ( color );
    int obelisks_visited = m_player_ptr->get_obelisk_count( color );
    int pieces_to_show = ( (obelisks_visited * k_total_number_of_pieces)/required_obelisks );

    // Set text.
	std::string visit_text = replace_keywords( k_text_puzzle_visit, "%visited", format_string("%d", obelisks_visited),
                                    "%required", format_string("%d", required_obelisks) );
	//std::string visit_text = replace_keywords( help.get_help( "progress" ), "%visited", format_string("%d", obelisks_visited),
    //                                "%required", format_string("%d", required_obelisks) );
    m_visit_text_window_ptr->set_text ( visit_text );

    // Visited all obelisks - show map.
    if (obelisks_visited >= m_map_ptr->get_required_obelisks( color ) )
    {
        display_artifact_location();
    }
    else
    {
        // Show puzzle pieces.
        reveal_picture ( pieces_to_show );
    }
}

/*
** Clicked close button.
*/
void t_puzzle_window::close_click( t_button *button_ptr )
{

    if (m_treasure_map_window_ptr)
        m_treasure_map_window_ptr->close();
    
    m_fading = 0;
    close();

}
